package reso.examples.gobackn.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.RangeType;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class GuiView extends JPanel implements ChangeListener {

	private GuiJfreeChartModel guiJfreeChartModel;
	private XYSeries seriesSS;

	private XYSeries seriesCA;

	private XYSeries seriesFR;
	private XYSeries seriesTO;
	private XYSeries seriesSST;

	private XYSeries lastModif;
	private ChartPanel chartPanel;
	private JLabel jlValCwnd = new JLabel();
	private JLabel jlValSsthresh = new JLabel();

	GuiView(GuiJfreeChartModel guiJfreeChartModel) {
		this.guiJfreeChartModel = guiJfreeChartModel;
		this.guiJfreeChartModel.addListener(this);
		this.setLayout(new BorderLayout());
		init();
		JLabel jlCwnd = new JLabel("CWND =");
		JLabel jlSsthresh = new JLabel("SSTHRESH =");

		JPanel jp = new JPanel(new GridLayout(2, 2, 0, 0));
		jp.add(jlCwnd);
		jp.add(jlValCwnd);
		jp.add(jlSsthresh);
		jp.add(jlValSsthresh);

		this.add(jp, BorderLayout.EAST);

	}

	@Override
	public synchronized void stateChanged(ChangeEvent e) {
		jlValCwnd.setText(guiJfreeChartModel.getCwnd() + "");
		jlValSsthresh.setText(guiJfreeChartModel.getSsthresh() + "");
		int x = guiJfreeChartModel.getCounterRtt();
		XYSeries toAdd;

		switch (guiJfreeChartModel.getCurrentOperation()) {
		case SLOW_START:
			toAdd = seriesSS;
			break;
		case CONGESTION_AVOIDANCE:
			toAdd = seriesCA;
			break;
		case FAST_RECOVERY:
			toAdd = seriesFR;
			break;
		case TIMEOUT:
			toAdd = seriesTO;
			break;
		default:
			return;
		}

		if (toAdd != lastModif) {

			toAdd.add(lastModif.getMaxX(),
					lastModif.getY(lastModif.getItemCount() - 1));
			toAdd.add(x, guiJfreeChartModel.getCwnd());
			lastModif.add(lastModif.getMaxX(), null);
			lastModif = toAdd;
		} else {
			toAdd.add(x, guiJfreeChartModel.getCwnd());
		}
		if (seriesSST.getItemCount() == 0) {
			seriesSST.add(1, guiJfreeChartModel.getSsthresh());
		}
		seriesSST.add(x, guiJfreeChartModel.getSsthresh());
	}

	private void init() {
		seriesSS = new XYSeries("Slow Start");
		seriesSS.add(1, 1);
		seriesCA = new XYSeries("Congestion Avoidance");
		seriesFR = new XYSeries("Fast Recovery");
		seriesTO = new XYSeries("Timeout");
		seriesSST = new XYSeries("Treeshold");
		lastModif = seriesSS;
		final XYSeriesCollection dataset = new XYSeriesCollection();
		dataset.addSeries(seriesSS);
		dataset.addSeries(seriesCA);
		dataset.addSeries(seriesFR);
		dataset.addSeries(seriesTO);
		dataset.addSeries(seriesSST);

		final JFreeChart chart = createChart(dataset);
		this.chartPanel = new ChartPanel(chart);
		chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
		this.add(chartPanel);

	}

	/**
	 * Creates a chart.
	 * 
	 * @param dataset
	 *            the data for the chart.
	 * 
	 * @return a chart.
	 */
	private JFreeChart createChart(final XYDataset dataset) {

		// create the chart...
		final JFreeChart chart = ChartFactory.createXYLineChart(
				"GO Back N / TCP Reno", // chart
				// title
				"RTT", // x axis label
				"CWND", // y axis label
				dataset, // data
				PlotOrientation.VERTICAL, true, // include legend
				true, // tooltips
				false // urls
				);
		chart.setBackgroundPaint(Color.WHITE);
		final XYPlot plot = chart.getXYPlot();
		plot.setBackgroundPaint(Color.BLACK);
		plot.setDomainGridlinesVisible(false);
		plot.setRangeGridlinesVisible(false);
		final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
		renderer.setSeriesShapesVisible(0, false);
		renderer.setSeriesShapesVisible(1, false);
		renderer.setSeriesShapesVisible(2, false);
		renderer.setSeriesShapesVisible(3, false);
		renderer.setSeriesShapesVisible(4, false);

		renderer.setSeriesPaint(0, Color.GREEN);
		renderer.setSeriesPaint(1, Color.CYAN);
		renderer.setSeriesPaint(2, Color.ORANGE);
		renderer.setSeriesPaint(3, Color.RED);
		renderer.setSeriesPaint(4, Color.GRAY);

		plot.setRenderer(renderer);

		NumberAxis domain = (NumberAxis) plot.getDomainAxis();
		domain.setAutoRangeMinimumSize(50);
		domain.setRange(new Range(0, 50), false, false);
		domain.setRangeType(RangeType.POSITIVE);
		domain.setTickUnit(new NumberTickUnit(5));
		// domain.setVerticalTickLabels(true);
		NumberAxis range = (NumberAxis) plot.getRangeAxis();
		range.setAutoRangeMinimumSize(50);
		range.setRangeType(RangeType.POSITIVE);
		range.setRange(new Range(0, 50), false, false);

		return chart;
	}

}
